package utils;

import models.TA001;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by xuyang on 2018/1/11.
 */
public class ACARS620Parser {
    public ACARS620Parser() {
    }

    private static String[] parseHead(String rawMsg) throws ACARS620Exception {
        String[] result = null;
        int intIndex = rawMsg.indexOf("\r\n-  ");
        if(intIndex < 0) {
            intIndex = rawMsg.indexOf("\n-  ");
        }

        if(intIndex > 0) {
            String strHead = rawMsg.substring(0, intIndex);
            result = strHead.replace("\r\n", "\n").split("\n");
            if(result.length < 4) {
                throw new ACARS620Exception("parse message head error missing lines current " + result.length + " lines");
            }
        } else {
            result = rawMsg.replace("\r\n", "\n").split("\n");
            if(result.length < 4) {
                throw new ACARS620Exception("parse message head error missing lines current " + result.length + " lines");
            }
        }

        return result;
    }

    private static Map<String, String> parseLine1(String line1) throws ACARS620Exception {
        HashMap result = new HashMap();
        Pattern pattern = Pattern.compile("(\\x01)(QU)((?:\\s+\\S{7}){1,16})");
        Matcher matcher = pattern.matcher(line1);
        if(matcher.find()) {
            result.put("Priority", matcher.group(2).trim());
            result.put("RecvAddress", matcher.group(3).trim());
            return result;
        } else {
            throw new ACARS620Exception("parse message line1 error");
        }
    }

    private static Map<String, String> parseLine2(String line2) throws ACARS620Exception {
        HashMap result = new HashMap();
        Pattern pattern = Pattern.compile("(\\.)(\\S{7}{1})((?:\\s{1}\\d{6})?)");
        Matcher matcher = pattern.matcher(line2);
        if(matcher.find()) {
            result.put("SendAddress", matcher.group(2).trim());
            result.put("SendTime", matcher.group(3).trim());
            return result;
        } else {
            throw new ACARS620Exception("parse message line2 error");
        }
    }

    private static Map<String, String> parseLine3(String line3) throws ACARS620Exception {
        HashMap result = new HashMap();
        Pattern pattern = Pattern.compile("(\\x02)(\\S{3})");
        Matcher matcher = pattern.matcher(line3);
        if(matcher.find()) {
            result.put("SMI", matcher.group(2).trim());
            return result;
        } else {
            throw new ACARS620Exception("parse message line3 error");
        }
    }

    private static Map<String, String> parseLine4(String line4) {
        HashMap result = new HashMap();
        Pattern pattern = Pattern.compile("((?:FI|AN|GL|AP|TP|MA|AD|OT|OF|ON|IN|FB|DS)\\s{1}[\\S&&[^/]]+)");
        Matcher matcher = pattern.matcher(line4);

        while(matcher.find()) {
            String[] strValue = matcher.group().split(" ");
            result.put(strValue[0].trim(), strValue[1].trim());
        }

        return result;
    }

    private static Map<String, String> parseLine5(String line5) {
        HashMap result = new HashMap();
        Pattern pattern = Pattern.compile("(DT)((?:\\s{1}\\S+))((?:\\s{1}\\S+))((?:\\s{1}\\d{6}))((?:\\s{1}\\S+))");
        Matcher matcher = pattern.matcher(line5);
        if(matcher.find()) {
            result.put("DSP", matcher.group(2).trim());
            result.put("RGS", matcher.group(3).trim());
            result.put("RGSTime", matcher.group(4).trim());
            result.put("MSN", matcher.group(5).trim());
        }

        return result;
    }

    private static String parseFreeText(String rawMsg) throws ACARS620Exception {
        String result = null;
        int intIndex = rawMsg.indexOf("\r\n-  ");
        if(intIndex < 0) {
            intIndex = rawMsg.indexOf("\n-  ");
        }

        if(intIndex > 0) {
            result = rawMsg.substring(intIndex).trim().replace("-  ", "");
        }

        return result;
    }

    public static TA001 parse(String rawMsg) throws ACARS620Exception {
        String[] head = parseHead(rawMsg);
        if(head != null && head.length > 0) {
            TA001 msg = new TA001();
            Map map = parseLine1(head[0]);
            if(map.containsKey("Priority")) {
                msg.setPriority(Strings.nullToEmpty((String)map.get("Priority")));
            }

            if(map.containsKey("RecvAddress")) {
                msg.setRcv_address((String)map.get("RecvAddress"));
            }

            map = parseLine2(head[1]);
            if(map.containsKey("SendAddress")) {
                msg.setSnd_address(Strings.nullToEmpty((String)map.get("SendAddress")));
            }

            if(map.containsKey("SendTime")) {
                String timeStr = (String)map.get("SendTime");
                Date dt = DateTimeFormat.forPattern("ddHHmm").parseDateTime(timeStr).toDate();

                msg.setGateway_time(dt);
            }

            map = parseLine3(head[2]);
            if(map.containsKey("SMI")) {
                msg.setSmi(Strings.nullToEmpty((String)map.get("SMI")));
            }

            map = parseLine4(head[3]);
            if(map.containsKey("FI")) {
                msg.setFlight_id(Strings.nullToEmpty((String)map.get("FI")));
            }

            if(map.containsKey("AN")) {
                msg.setAircraft_id(Strings.nullToEmpty((String)map.get("AN")));
            }

//            if(map.containsKey("MA")) {
//                msg.setMa(Strings.nullToEmpty((String)map.get("MA")));
//            }

            if(head.length >= 5) {
                map = parseLine5(head[4]);
                if(map.containsKey("DSP")) {
                    msg.setDsp(Strings.nullToEmpty((String)map.get("DSP")));
                }

                if(map.containsKey("RGS")) {
                    msg.setRgs(Strings.nullToEmpty((String)map.get("RGS")));
                }

                if(map.containsKey("RGSTime")) {
                    msg.setBep_time(Strings.nullToEmpty((String)map.get("RGSTime")));
                }

                if(map.containsKey("MSN")) {
                    msg.setMsn(Strings.nullToEmpty((String)map.get("MSN")));
                }
            }

            msg.setFreeText(parseFreeText(rawMsg));
            return msg;
        } else {
            return null;
        }
    }

    public static String clearDatagramControlChar(String datagramText) {
        String p = datagramText.trim().substring(0,1);
        p = Pattern.quote(p);

        return datagramText
                .replaceFirst(Pattern.quote("&#1;"), "\001")
                .replaceFirst(Pattern.quote("&#2;"), "\002")
                .replaceFirst(Pattern.quote("&#3;"), "\003")
                .replaceFirst(p, "\001").replaceFirst(p, "\002").replaceFirst(p, "\003");
    }
}
